package com.lbj.mall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lbj.mall.common.constant.ProductAttrType;
import com.lbj.mall.common.utils.PageUtils;
import com.lbj.mall.common.utils.Query;
import com.lbj.mall.product.dao.AttrAttrgroupRelationDao;
import com.lbj.mall.product.dao.AttrDao;
import com.lbj.mall.product.dao.AttrGroupDao;
import com.lbj.mall.product.dao.CategoryDao;
import com.lbj.mall.product.entity.AttrAttrgroupRelationEntity;
import com.lbj.mall.product.entity.AttrEntity;
import com.lbj.mall.product.entity.AttrGroupEntity;
import com.lbj.mall.product.entity.CategoryEntity;
import com.lbj.mall.product.entity.vo.AttrRespVo;
import com.lbj.mall.product.entity.vo.AttrVo;
import com.lbj.mall.product.service.AttrGroupService;
import com.lbj.mall.product.service.AttrService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao relationDao;
    @Autowired
    private CategoryDao categoryDao;
    @Autowired
    private AttrGroupDao attrGroupDao;
    @Autowired
    private AttrGroupService attrGroupService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    // 因为这里操作了2张表，所以需要事务
    @Transactional
    @Override
    public void saveAttrAndAttrGroup(AttrVo vo) {
        // 1.保存属性信息到属性表中去
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(vo, attrEntity);
        this.save(attrEntity);

        // 如果是销售属性则不需要添加中间表
        if(ProductAttrType.BASE.getCode() == vo.getAttrType()){
            // 2.保存属性id和属性分组id到中间表中去
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            // 注意这里：保存信息时attrId从前端传过来的数值是null
            // 但是在经过 this.save(attrEntity); 后，这个 attrEntity 中就有了 attrId 这个值
            // 就是说当保存玩数据之后，attrEntity中就有了主键id了
            relationEntity.setAttrId(attrEntity.getAttrId());
            relationEntity.setAttrGroupId(vo.getAttrGroupId());

            relationDao.insert(relationEntity);
        }
    }

    @Override
    public PageUtils queryBaseOrSaleList(Map<String, Object> params, int attrTypeInt, Long categoryId) {
        QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>();

        wrapper.eq("attr_type",attrTypeInt);

        // 当查询条件有列表id时，则添加类别id搜索条件
        if (categoryId != null && categoryId != 0) {
            wrapper.and(item -> item.eq("catelog_id", categoryId));
        }
        // 当查询条件有关键字时，添加关键字搜索条件
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            // 这里的 and 是因为当列表id非0时，所以这里要添加and ===> A and (B or C)
            wrapper.and(item -> {
                item.eq("attr_id", key).or().like("attr_name", key);
            });
        }

        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), wrapper);
        PageUtils pageUtils = new PageUtils(page);

        // 这里还不够，我们还需要传入所属分类（catelogName）和所属分组（groupName）的信息
        // 所属分类的名字可以通过 categoryId 查询 pms_catetory 表
        // 所属分组的名字可以通过 attrId 查询 pms_attr_attrgroup_relation 表中的 attr_group_id 字段
        // 再通过 attr_group_id 查询 pms_attr_group 表中的 attr_group_name
        // 注意：这里为什么不使用连表查询，就是因为连表查询会造成笛卡尔积的情况，因此在数据很多的时候一定要避免连表查询
        List<AttrEntity> records = page.getRecords();
        List<AttrRespVo> resultList = records.stream().map(item -> {
            AttrRespVo vo = new AttrRespVo();
            // 拷贝字段，前一个参数是来源，第二个参数是被拷贝的字段
            BeanUtils.copyProperties(item, vo);

            // 设置所属分类的名字
            CategoryEntity categoryEntity = categoryDao.selectOne(
                    new QueryWrapper<CategoryEntity>().eq("cat_id", item.getCatelogId()));
            if (categoryEntity != null) {
                vo.setCatelogName(categoryEntity.getName());
            }

            // 设置所属分组的名字 // 销售属性没有属性分组
            if(attrTypeInt == ProductAttrType.BASE.getCode()){
                AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = relationDao.selectOne(
                        new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", item.getAttrId())
                );
                if (attrAttrgroupRelationEntity != null) {
                    AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrAttrgroupRelationEntity.getAttrGroupId());
                    if (attrGroupEntity != null) {
                        vo.setGroupName(attrGroupEntity.getAttrGroupName());
                    }
                }
            }
            return vo;
        }).collect(Collectors.toList());
        // 将封装好的数据设置到数据集中
        pageUtils.setList(resultList);
        return pageUtils;
    }

    @Override
    public List<Long> queryCanSearchAttrId(List<Long> attrIdList) {
        return baseMapper.queryCanSearchAttrId(attrIdList);
    }

    @Override
    public AttrRespVo getInfoFromAttrId(Long attrId) {
        AttrRespVo vo = new AttrRespVo();
        // 查询基本信息
        AttrEntity attrEntity = getById(attrId);
        BeanUtils.copyProperties(attrEntity, vo);
        // 还需要设置另外 4 个字段
        CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
        if (categoryEntity != null) {
            // 设置分类名字
            vo.setCatelogName(categoryEntity.getName());
            // 设置分类3层路径Id
            List<Long> catelogList = new ArrayList<>(3);
            List<Long> catelogPath = attrGroupService.getCatelogPath(catelogList, attrEntity.getCatelogId());
            // 这个路径是倒叙的，我们要反转一下才能使用
            Collections.reverse(catelogList);
            vo.setCatelogPath(catelogPath);
        }
        // 判断如果当前属性是销售属性则不需要查找属性分组
        if(ProductAttrType.BASE.getCode() == attrEntity.getAttrType()){
            AttrAttrgroupRelationEntity relationEntity = relationDao.selectOne(
                    new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId)
            );
            if (relationEntity != null) {
                vo.setAttrGroupId(relationEntity.getAttrGroupId());
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId());
                if (attrGroupEntity != null) {
                    vo.setGroupName(attrGroupEntity.getAttrGroupName());
                }
            }
        }
        return vo;
    }

    /**
     * 这里涉及到了2张表
     * 1. 要更新数据的属性表中
     * 2. 要更新数据到属性表和属性组的中间表中
     */
    @Transactional
    @Override
    public void updateAttrAndAttrGroup(AttrVo vo) {
        // 1.更新数据表属性表中
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(vo, attrEntity);
        updateById(attrEntity);

        // 销售属性没有属性分组
        if(ProductAttrType.BASE.getCode() == vo.getAttrType()){
            // 2.更新数据到中间表中

            // 2.1 准备实体类
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            relationEntity.setAttrId(vo.getAttrId());
            relationEntity.setAttrGroupId(vo.getAttrGroupId());

            // 2.2 创建一个查询条件：中间表中 attr_id = vo.getAttrId() 的数据
            UpdateWrapper<AttrAttrgroupRelationEntity> wrapper =
                    new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", vo.getAttrId());

            // 3.3 判断是否有满足条件的数据，如果有就更新数据，如果没有则插入数据
            Long aLong = relationDao.selectCount(wrapper);
            if (aLong == null || aLong == 0) {
                // 插入数据
                relationDao.insert(relationEntity);
            } else {
                // 更新数据
                relationDao.update(relationEntity, wrapper);
            }
        }
    }
}